Teaser CONFidence CTF 2019 WriteUp


Web 50

前言

在hpdoger师傅的分享学到了很多~

题目链接:https://web50.zajebistyc.tf, 貌似还没关 各位师傅可以还可以抓紧时间去玩一下

测试了一下功能点,一个注册功能(注册即登陆),一个提交漏洞报告页面(给管理员)。

一共有这么几个可控点:

注册处用户名可控,会在profile页面输出,但是尝试注册了用户名为'"<敏感字符,结果是被实体编码:
image_1d6itjpjb1adge7kns71dd1m4t9.png-43kB

其次,在注册的时候会有一次跳转,url像下面这样:
image_1d6itne4559l1iffqnlamkv45m.png-22.6kB

抓包分析了一下,服务端强制location跳转,所以这里是不可控的。
image_1d6itqtci11t66fv2n438v82h13.png-207.5kB

进到个人页面:
image_1d6itubg81m7rlh8c711p6ffmi1t.png-60.5kB

看到这个url,很容易想到去尝试是否有越权访问admin的问题:
image_1d6iu02d810vukbtlg51c7u1npr2a.png-31.9kB

显然,根据这两个页面的差异,我们容易想到这个题想让我们根据xss来读管理员的secret字段。

再来分析一下这个表单,有这么一些可控的点,但有实体编码,仔细看我们会发现selectvalue属性没有用"包裹, 其次这里还有一个限制即图片只能100*100的大小
image_1d6iudu0a19h7t26huad691e0u3k.png-395.7kB

select标签可以使用onfocus()autofocus配合来进行xss,payload:
30 onfocus=javascript:alert(1) autofocus
image_1d6ivlr3sa1d1sbl3u11jarqes4e.png-315.7kB
image_1d6ivlc7rv8rllo1dbq1d5kldi41.png-71.6kB

可以去看一下p师傅在2013年就总结了一篇各种标签的利用姿势:那些年我们没能bypass的xss filter

那么问题来了,这里只是self-xss,还没想到如何打出危害。

值得注意的是,上传头像的filename参数,虽然不能插入字符,但是可以指定任意后缀名(当然他检测了图片大小必须为100*100),

image_1d6j0aoj11kassf2ep26ivnon4r.png-230.8kB

(似乎也没啥用)

bmp xss

后来发现一个图片xss的思路,原理简而言之即通过修改图片结构使得其成为一个js语法合法的文件,接着利用浏览器对内容的检测差异导致恶意图片被解析成js。

在这里,复现这个问题的时候,我使用了外国一个大牛的脚本:https://pastebin.com/04y7ee3u, 但意外的是,我根据教程生成了payload,但是在chrome和Firefox都尝试打开后,并没有弹窗,当时想的是服务端可能会对图片内容进行判断,从而返回的content-type可能不为图片,从而导致误导浏览器解析为js,后来我在ie下测试时,它弹窗了,我尝试分析其数据包,在生成的payload中会尝试用imgscript标签两次加载图片:
image_1d6k43e9q1cc41al2570ppi29q6f.png-34.7kB

而当我分析这两个请求的差异,结果并无差异(但只有script标签会弹窗),所以原因可想而知,出在浏览器上,猜想是浏览器会对内容判断的差异造成js执行
image_1d6k42d1n1gsio8k1amjuec14ol62.png-136.7kB

ie在进行种别判断的时候,不单考虑content-type,还根据content内容进行判断导致。
image_1d6k3fc9a14p66jm1ipftf62p858.png-118.4kB

参考了一下IE content种别判断和图片magic bite、content_tpe之间的关系表,在文末参考链接中有原文,
image_1d6k4q8k91cu4cop1v1infntfh6s.png-35.5kB

到这里可能想到bmp必须得用script引入才能触发。

但后来hpdoher师傅弱口令登了个国外队伍的号子嫖了个现成的bmp图片打到了flag..(这里挺迷惑的,不太懂他bot怎么解析的)

image_1d6k6e6jqsh61shg15jk1pn612l579.png-134kB

bmpinjector.pyimage_1d6k3q8u51a68g24ot613bf10ca5l.png-78.2kB

svg xss

在hackone上有一个svg xss的案例: https://hackerone.com/reports/148853
将其图片长宽修改后,将payload发送

1
2
3
4
5
6
7
8
9
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" baseProfile="full" xmlns="https://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert('This app is probably vulnerable to XSS attacks!');
</script>
</svg>

image_1d6k708dj1sqj193mcd518141usd8j.png-395.6kB

image_1d6k6t6d78iu1aa8tj3pcaveu7m.png-85.6kB

然后就很简单了,将admin的源码打回vps
image_1d6k7abmntd712rr1c9o173f1gji90.png-375.5kB

image_1d6k7bkl9oet1o6f152b1fk1ihqb0.png-105.5kB
flag: p4{15_1t_1m4g3_or_n0t?}

具体的原理可以学习这篇文文章:深入理解浏览器解析机制和XSS向量编码

缓存投毒

这算非预期解法,前面我们提到了select标签处有一个self-xss,但是一直没有利用点,后来在hpdoger师傅的交流中,从返回包中可以看到这题中用到了cloudFlare,于是尝试了一下缓存投毒,将self-xss变成可利用的反射型xss。

这里有个特征,我们如果注册的名字为passer8y.js,url中会以passer8y.js为文件名:
image_1d6k9213i1uurpqh1k0n5lspg7bq.png-57kB

接着发送这样一个数据包, 可以看到被缓存到cloudflare里去了。
image_1d6k9rtlq1vnh1icca2a2dd10bcd1.png-321.1kB

直接访问:https://web50.zajebistyc.tf/profile/passer8y.js, 自动进行了一次跳转,所以我们成功将xss缓存进了cloudflare。
image_1d6k9vckj3rm5ik152p6j2incde.png-56.6kB

但是bot似乎不会跟进location跳转,所以我们得构造其他payload去打源码

这里在种缓存的时候有个小点需要注意,我们注册xxx.js的账户完了点进profile页面那次就会缓存到cloudflare,然后我们再次修改profile页面资料时,并不会修改cloudflare的缓存。所以我们要提前抓好注册和修改profile的包(或者写脚本),第一次访问就得种上我们的payload。

这里可以用js的Fetch API 去读取admin的profile页面,然后在回调的过程创建一个image图片将返回内容打到我们vps。参考mdn的文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

复现的时候貌似bot挂了,暂时先这样吧。

My admin panel

考察php弱类型绕过,一般我们gpc传入的数据服务端接受到的都是字符型(而弱类型比较需要字符串和数值类型的两个数据进行弱类型比较),而如果此时使用了类似于json_decode()这样的解码函数,我们仍可以传入数值类型的数据:
这样传入的hash值为数值类型:{"hash": 389}
而这样为字符型:{"hash": "389"}

image_1d6kllkqk1mv9i7vl0i7uh1q7e9.png-65.2kB

参考:
image xss 1.图片发生xss攻击的条件、原因及对策
xss link&svg黑魔法
hackone-Stored XSS using SVG
Web 50